package com.yangchuang.openpicture.exception;

import com.yangchuang.openpicture.communication.ResponseMessage;
import com.yangchuang.openpicture.communication.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    // -------------------------- 1. 自定义业务异常处理 --------------------------
    @ExceptionHandler(BussinessException.class)
    public ResponseMessage<?> handleBussinessException(BussinessException ex) {
        // 打印业务异常日志（级别用INFO，因为是可控异常，无需告警）
        log.info("业务异常捕获：code={}, message={}", ex.getCode(), ex.getMessage());
        // 返回自定义的业务异常响应
        return ResponseMessage.fail(ex.getCode(), ex.getMessage());
    }

    // -------------------------- 2. 参数校验异常处理 --------------------------

    /**
     * 处理@RequestBody参数校验异常（如Controller方法参数加@Valid注解）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseMessage<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        // 1. 获取具体的校验失败信息（如“用户名不能为空”“年龄必须大于18”）
        String errorMsg = ex.getBindingResult().getFieldErrors().stream()
                // 收集所有字段的错误信息（避免只返回第一个错误）
                .map(fieldError -> fieldError.getField() + "：" + fieldError.getDefaultMessage())
                .reduce((msg1, msg2) -> msg1 + "；" + msg2) // 拼接多个错误信息
                .orElse(ResultCode.PARAM_INVALID.getMessage()); // 兜底：无具体信息时用默认消息

        // 2. 打印校验异常日志（级别用WARN，提示开发人员参数问题）
        log.warn("参数校验异常捕获：{}", errorMsg);

        // 3. 返回参数无效响应（携带具体错误信息）
        return ResponseMessage.fail(ResultCode.PARAM_INVALID.getCode(), errorMsg);
    }

    /**
     * 处理@RequestParam/@PathVariable参数校验异常（如Controller方法参数加@NotNull）
     */
    @ExceptionHandler(BindException.class)
    public ResponseMessage<?> handleBindException(BindException ex) {
        // 逻辑与上面一致，复用错误信息获取逻辑
        String errorMsg = ex.getBindingResult().getFieldErrors().stream()
                .map(fieldError -> fieldError.getField() + "：" + fieldError.getDefaultMessage())
                .reduce((msg1, msg2) -> msg1 + "；" + msg2)
                .orElse(ResultCode.PARAM_INVALID.getMessage());
        log.warn("参数绑定异常捕获：{}", errorMsg);
        return ResponseMessage.fail(ResultCode.PARAM_INVALID.getCode(), errorMsg);
    }


    // -------------------------- 3. 通用异常处理 --------------------------
    @ExceptionHandler(Exception.class)
    public ResponseMessage<?> handleException(Exception ex) {
        // 打印通用异常日志（级别用ERROR，因为是不可控异常，需要告警排查）
        // 打印堆栈信息（关键！否则无法定位异常位置）
        log.error("系统未知异常捕获：", ex);
        // 返回系统内部错误响应（不对外暴露具体异常信息，避免安全风险）
        return ResponseMessage.fail(ResultCode.INTERNAL_ERROR);
    }

}
